www.gusucode.com > VC++ 编写软件自动升级服务源代码 > VC++ 编写软件自动升级服务源代码/gusucode/updater_src0.8.1.6/Install.cpp

    /********************************************************************
	created:	2005/03/02
	created:	2:3:2005   10:55
	filename: 	Install.cpp
	file path:	Updater
	file base:	Install
	file ext:	cpp
	author:		Geert van Horrik
	
	purpose:	
*********************************************************************/

//*********************************************************************
// INCLUDES
//*********************************************************************

#include "stdafx.h"
#include "Updater.h"
#include "Install.h"

//*********************************************************************
// MESSAGE MAP
//*********************************************************************

BEGIN_MESSAGE_MAP(CInstall, CWinThread)
	ON_THREAD_MESSAGE(WMU_INSTALL_STATUS, OnInstallStatus)
	ON_THREAD_MESSAGE(WMU_ERROR, OnError)
	ON_THREAD_MESSAGE(WMU_WARNING, OnWarning)
	ON_THREAD_MESSAGE(WMU_WARNING_COMPLETE, OnWarningComplete)
	ON_THREAD_MESSAGE(WMU_QUESTION, OnQuestion)
	ON_THREAD_MESSAGE(WMU_QUESTION_ANSWER, OnQuestionAnswer)
	ON_THREAD_MESSAGE(WMU_INSTALL_COMPLETE, OnInstallComplete)
	ON_THREAD_MESSAGE(WMU_SETPARENT, OnSetParent)
	ON_THREAD_MESSAGE(WMU_THREADMESSAGE, OnThreadMessage)
END_MESSAGE_MAP()

//*********************************************************************
// CONSTRUCTOR & DESTRUCTOR
//*********************************************************************

IMPLEMENT_DYNCREATE(CInstall, CWinThread)

//=====================================================================

CInstall::CInstall()
{
}

//=====================================================================

CInstall::~CInstall()
{
}

//*********************************************************************
// PUBLIC FUNCTIONS
//*********************************************************************

BOOL CInstall::InitInstance()
{
	// Log
	CLog::Instance()->Log(_T("CInstall::InitInstance()"));

	// Set parent to NULL
	m_pParent = NULL;

	// We are not started yet
	m_bStarted = false;
	
	// Reserve memory for buffer
	m_szFilename = (TCHAR *)malloc(sizeof(TCHAR) * 500);
	ZeroMemory(m_szFilename, sizeof(TCHAR) * 500);

	// Start install files thread
	m_pInstallFiles = (CInstallFiles *)AfxBeginThread(RUNTIME_CLASS(CInstallFiles),
		THREAD_PRIORITY_NORMAL,
		0,
		0,
		NULL);

	// Start install ini thread
	m_pInstallIni = (CInstallIni *)AfxBeginThread(RUNTIME_CLASS(CInstallIni),
		THREAD_PRIORITY_NORMAL,
		0,
		0,
		NULL);
	
	// Start install registry thread
	m_pInstallRegistry = (CInstallRegistry *)AfxBeginThread(RUNTIME_CLASS(CInstallRegistry),
		THREAD_PRIORITY_NORMAL,
		0,
		0,
		NULL);

	// Init singleton classes
	m_pFunctions = CFunctions::Instance();
	m_pSettings = CSettings::Instance();
	m_pUpdateInfo = CUpdateInfo::Instance();
	m_pLanguage = CLanguage::Instance();
	m_pPath = CPath::Instance();

	// Extract UpdaterCopy.exe from this executable
	if (m_pUpdateInfo->GetSelfUpdate())
		ExtractUpdaterCopy();

	// Set parent
	m_pInstallFiles->PostThreadMessage(WMU_SETPARENT, (WPARAM)this, 0);
	m_pInstallIni->PostThreadMessage(WMU_SETPARENT, (WPARAM)this, 0);
	m_pInstallRegistry->PostThreadMessage(WMU_SETPARENT, (WPARAM)this, 0);

	// Suspend all threads
	/*m_pInstallFiles->SuspendThread();
	m_pInstallIni->SuspendThread();
	m_pInstallRegistry->SuspendThread();*/

	// Set some default values
	m_iPreviousActionsPerformed = 0;
	m_iTotalActionsPerformed = 0;

	return TRUE;
}

//=====================================================================

int CInstall::ExitInstance()
{
	// Log
	CLog::Instance()->Log(_T("CInstall::ExitInstance()"));

	// Destroy threads
	m_pInstallFiles->PostThreadMessage(WM_QUIT, 0, 0);
	m_pInstallIni->PostThreadMessage(WM_QUIT, 0, 0);
	m_pInstallRegistry->PostThreadMessage(WM_QUIT, 0, 0);

	// Auto clean-up thread
	m_bAutoDelete = TRUE;

	// Call original function
	return CWinThread::ExitInstance();
}

//*********************************************************************
// PRIVATE FUNCTIONS
//*********************************************************************

void CInstall::InstallPart(int iPart)
{
	// Set this part as active part
	m_iCurrentPart = iPart;

	// Check what part we are
	switch (m_iCurrentPart)
	{
	case INSTALL_FILES:
		//m_pInstallFiles->ResumeThread();
		m_pInstallFiles->PostThreadMessage(WMU_INSTALL_START, 0, 0);
		break;

	case INSTALL_INI:
		//m_pInstallIni->ResumeThread();
		m_pInstallIni->PostThreadMessage(WMU_INSTALL_START, 0, 0);
		break;

	case INSTALL_REGISTRY:
		//m_pInstallRegistry->ResumeThread();
		m_pInstallRegistry->PostThreadMessage(WMU_INSTALL_START, 0, 0);
		break;
	}
}

//=====================================================================

void CInstall::InstallNextPart()
{
	// Suspend current thread
	switch (m_iCurrentPart)
	{
	case INSTALL_FILES:
		m_pInstallFiles->PostThreadMessage(WM_QUIT, 0, 0);
		//m_pInstallFiles->SuspendThread();
		break;
		
	case INSTALL_INI:
		m_pInstallIni->PostThreadMessage(WM_QUIT, 0, 0);
		//m_pInstallIni->SuspendThread();
		break;
		
	case INSTALL_REGISTRY:
		m_pInstallRegistry->PostThreadMessage(WM_QUIT, 0, 0);
		//m_pInstallRegistry->SuspendThread();
		break;
	}

	// Update the part
	m_iCurrentPart++;

	// Are there still parts left?
	if (m_iCurrentPart < INSTALL_MAX)
	{
		// Install next part
		InstallPart(m_iCurrentPart);
	}
	else
	{
		// We are ready, progress MUST be 100%
		PostMessageToParent(WMU_UPDATE_GUI_FILEPROGRESS, 100, (LPARAM)m_szFilename);
		PostMessageToParent(WMU_UPDATE_GUI_TOTALPROGRESS, 100, 0);

		// Send message to parent that we are ready
		PostMessageToParent(WMU_TASK_COMPLETE, TASK_INSTALL, 0);
		
		// Exit the thread
		PostThreadMessage(WM_QUIT, 0, 0);
	}
}

//=====================================================================

void CInstall::ExtractUpdaterCopy()
{
	// Declare variables
	HRSRC resource;
	HGLOBAL resourceData;
	long * lpResLock;
	DWORD dwResourceSize;
	CString sUpdaterLocation, sResourceName, sUpdaterCopyLocation;

	// Get updater location
	sUpdaterLocation.Format(m_pPath->GetPathUpdaterExecutable());

	// Find the right resource
	sResourceName.Format(_T("#%d"), MAKEINTRESOURCE(IDR_UPDATERCOPY));
	resource = FindResource(NULL, sResourceName, _T("Bin"));

	// Load the executable resource
	resourceData = LoadResource(NULL, resource);

	// Get start address of resource
	lpResLock = (long *) LockResource(resourceData);

	// Get size of resource
	dwResourceSize = SizeofResource(NULL, resource);

	try
	{
		// Set up filename
		sUpdaterCopyLocation.Format(_T("%s\\%s"), m_pPath->GetPathTemp(), _T("UpdaterCopy.exe"));

		// Create file
		CFile exeFile(sUpdaterCopyLocation, CFile::modeWrite | CFile::modeCreate);

		// Wait until class is created
		Sleep(100);

		// Write data to executable
		exeFile.Write(lpResLock, dwResourceSize);

		// Close executable
		exeFile.Close();
	}

	// If there were any errors, catch them
	catch (CException * pEx)
	{
#if defined _DEBUG || defined _BETA
		pEx->ReportError();
#endif
		// Delete exception object to prevent leaks
		pEx->Delete();
	}
}

//=====================================================================

void CInstall::PostMessageToParent(UINT message, WPARAM wParam, LPARAM lParam)
{
	// Check if parent is still valid
	if (!IsBadReadPtr(m_pParent, sizeof(CWinThread *)))
	{
		// Send message
		m_pParent->PostThreadMessage(message, wParam, lParam);
	}
}

//=====================================================================

void CInstall::OnInstallStatus(WPARAM wParam, LPARAM lParam)
{
	// Declare variables
	CString sTemp;
	int iFileProgress, iTotalProgress;
	
	// Calculate action count every time to be as precise as possible
	m_iActionCount = m_pInstallFiles->GetActionCount();
	m_iActionCount += m_pInstallIni->GetActionCount();
	m_iActionCount += m_pInstallRegistry->GetActionCount();

	// Get status information
	InstallStatus * pInstallStatus = (InstallStatus *)wParam;

	// Get name
	lstrcpy(m_szFilename, pInstallStatus->sTitle);

	// Check if there is a positive difference between previous and current action count
	if (pInstallStatus->iTotalActionsPerformed - m_iPreviousActionsPerformed > 0)
	{
		// Update the difference
		m_iTotalActionsPerformed += pInstallStatus->iTotalActionsPerformed - m_iPreviousActionsPerformed;
	}

	// Save current action count so we can compare
	m_iPreviousActionsPerformed = pInstallStatus->iTotalActionsPerformed;

	// Calculate % of file
	if (pInstallStatus->iFileActions != 0)
	{
		iFileProgress = (pInstallStatus->iFileActionsPerformed * 100) / pInstallStatus->iFileActions;
	}
	else
	{
		iFileProgress = 0;
	}
	
	// Calculate % of total progress
	if (m_iActionCount != 0)
	{
		iTotalProgress = (m_iTotalActionsPerformed * 100) / m_iActionCount;
	}
	else
	{
		iTotalProgress = 0;
	}

	// Should we send information to parent?
	if (m_iFileProgress != iFileProgress)
		PostMessageToParent(WMU_UPDATE_GUI_FILEPROGRESS, iFileProgress, (LPARAM)m_szFilename);
	if (m_iTotalProgress != iTotalProgress)
		PostMessageToParent(WMU_UPDATE_GUI_TOTALPROGRESS, iTotalProgress, 0);

	// Update information
	m_iFileProgress = iFileProgress;
	m_iTotalProgress = iTotalProgress;
}

//=====================================================================

void CInstall::OnInstallComplete(WPARAM wParam, LPARAM lParam)
{
	// Install next part
	InstallNextPart();
}

//=====================================================================

void CInstall::OnError(WPARAM wParam, LPARAM lParam)
{
	// Send this error immediatly to parent
	PostMessageToParent(WMU_ERROR, wParam, (LPARAM)m_szFilename);
}

//=====================================================================

void CInstall::OnWarning(WPARAM wParam, LPARAM lParam)
{
	// Send this warning immediatly to parent
	PostMessageToParent(WMU_WARNING, wParam, (LPARAM)m_szFilename);
}

//=====================================================================

void CInstall::OnWarningComplete(WPARAM wParam, LPARAM lParam)
{
	// Send this complete message immediatly to childs
	m_pInstallFiles->PostThreadMessage(WMU_WARNING_COMPLETE, wParam, lParam);
	m_pInstallIni->PostThreadMessage(WMU_WARNING_COMPLETE, wParam, lParam);
	m_pInstallRegistry->PostThreadMessage(WMU_WARNING_COMPLETE, wParam, lParam);
}

//=====================================================================

void CInstall::OnQuestion(WPARAM wParam, LPARAM lParam)
{
	// Send this question immediatly to parent
	PostMessageToParent(WMU_QUESTION, wParam, lParam);
}

//=====================================================================

void CInstall::OnQuestionAnswer(WPARAM wParam, LPARAM lParam)
{
	// Check which question we are dealing with
	if (wParam == QUESTION_CLOSEAPPLICATION)
	{
		// Handle ourself
		if (lParam == QUESTIONRESULT_YES)
		{
			if (m_pUpdateInfo->GetCloseApplication() != CLOSE_USER)
			{
				// Close application
				if (!m_pFunctions->CloseApplication(m_pSettings->GetAppName(), m_pSettings->GetAppLocation()))
				{
					// Send error message
					PostMessageToParent(WMU_ERROR, ERROR_CLOSEAPP, (LPARAM)(LPCTSTR)m_pSettings->GetAppName());
					PostThreadMessage(WM_QUIT, 0, 0);
					return;
				}

				// Start installing first part
				InstallPart(INSTALL_FILES);
			}
			else
			{
				PostThreadMessage(WMU_THREADMESSAGE, THREAD_START, 0);
			}
		}
		else
		{
			// Send error message
			PostMessageToParent(WMU_ERROR, ERROR_CLOSEAPP, (LPARAM)(LPCTSTR)m_pSettings->GetAppName());
			PostThreadMessage(WM_QUIT, 0, 0);
			return;
		}
	}
	else
	{
		// Send this result message immediatly to childs
		m_pInstallFiles->PostThreadMessage(WMU_QUESTION_ANSWER, wParam, lParam);
		m_pInstallIni->PostThreadMessage(WMU_QUESTION_ANSWER, wParam, lParam);
		m_pInstallRegistry->PostThreadMessage(WMU_QUESTION_ANSWER, wParam, lParam);
	}
}

//=====================================================================

void CInstall::OnSetParent(WPARAM wParam, LPARAM lParam)
{
	// Set parent
	m_pParent = (CWinThread *)wParam;
}

//=====================================================================

void CInstall::OnThreadMessage(WPARAM wParam, LPARAM lParam)
{
	// Declare variables
	int iThreadAction = (int)wParam;
	
	// Check what task to perform for thread
	switch (iThreadAction)
	{
	case THREAD_START:
		// Are we already started?
		if (!m_bStarted)
		{
			// Check if app should be closed
			if (m_pUpdateInfo->GetCloseApplication() != CLOSE_FALSE)
			{
				// Is application running?
				if (m_pFunctions->ApplicationRunning(m_pSettings->GetAppLocation()))
				{
					// Ask user
					PostMessageToParent(WMU_QUESTION, QUESTION_CLOSEAPPLICATION, 
						(LPARAM)(LPCTSTR)m_pSettings->GetAppName());

					// Now wait for an answer
					return;
				}
			}

			// Application should be closed now, start installing first part
			InstallPart(INSTALL_FILES);
		}
		break;
		
	case THREAD_PAUSE:
		// Pause thread
		SuspendThread();
		break;
		
	case THREAD_RESUME:
		// Resume thread
		ResumeThread();
		break;
		
	case THREAD_CANCEL:
		// Exit thread
		PostThreadMessage(WM_QUIT, 0, 0);
		break;
		
	case THREAD_FINISH:
		// Exit thread
		PostThreadMessage(WM_QUIT, 0, 0);
		break;
	}
}

//=====================================================================